﻿using System;
using Simp.CodeModel;
using Simp.CodeModel.CoreFunctions;

namespace Simp.GraphModel
{
	/// <summary>Encapsulates a 2D-Point in cartesian coordinates.</summary>
	public class PointFunction : IFunction
	{
		private static readonly string[] PARAMETER_NAMES = new[] { "x", "y" };

		#region IFunction Members
		string IFunction.FunctionName
		{
			get { return "Point"; }
		}

		string[] IFunction.ParameterNames
		{
			get { return PARAMETER_NAMES; }
		}

		IFunctionParameterBinding[] IFunction.DefaultParameterValues
		{
			get { return FunctionHelper.EmptyBindings; }
		}

		IFunction IFunction.Simplify(SimplificationMode simplificationMode, params IFunction[] parameters)
		{
			return null;
		}

		IFunction IFunction.AcceptVisitor(IFunctionVisitor visitor)
		{
			return null;
		}
		#endregion

		/// <summary>Tries to compute the cartesian coordinates of point.</summary>
		/// <param name="boundPoint"></param>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public static bool TryGetCartesian(IFunction boundPoint, out double x, out double y)
		{
			BoundFunctionCalling point = FunctionHelper.TryGetBoundFunction<PointFunction>(boundPoint);

			if (point == null)
			{
				BoundFunctionCalling polar = FunctionHelper.TryGetBoundFunction<PolarFunction>(boundPoint);

				if (polar == null)
				{
					x = 0;
					y = 0;

					return false;
				}
				else
				{
					return PolarFunction.TryGetCartesian(polar.FunctionParameters[0], polar.FunctionParameters[1], out x, out y);
				}
			}
			else
			{
				INumericFunction xNumeric = point.FunctionParameters[0] as INumericFunction;
				INumericFunction yNumeric = point.FunctionParameters[1] as INumericFunction;

				if (xNumeric == null || yNumeric == null)
				{
					x = 0;
					y = 0;

					return false;
				}
				else
				{
					x = xNumeric.GetReal(true).Value;
					y = yNumeric.GetReal(true).Value;

					return true;
				}
			}
		}
	
		/// <summary>Tries to compute the polar coordinates of a cartesian point.</summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <param name="r"></param>
		/// <param name="theta"></param>
		/// <returns></returns>
		public static bool TryGetPolar(IFunction x, IFunction y, out double r, out double theta)
		{
			INumericFunction xNumeric = x as INumericFunction;
			INumericFunction yNumeric = y as INumericFunction;

			if (xNumeric == null || yNumeric == null)
			{
				r = 0;
				theta = 0;

				return false;
			}
			else
			{
				double xValue = xNumeric.GetReal(true).Value;
				double yValue = yNumeric.GetReal(true).Value;

				if (xValue == 0 && yValue == 0)
				{
					r = 0;
					theta = 0;

					return true;
				}
				else
				{
					r = Math.Sqrt(xValue * xValue + yValue * yValue);
					theta = Math.Atan2(yValue, xValue) * 180 / Math.PI;

					return true;
				}
			}
		}
	}
}